﻿using DevExpress.Xpo;
using DevExpress.Xpo.DB;
using DevExpress.Xpo.Metadata;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DBUtility
{
    public class XpoHelper
    {
        public static Session GetNewSession()
        {
            return new Session(DataLayer);
        }

        public static UnitOfWork GetNewUnitOfWork()
        {
            return new UnitOfWork(DataLayer);
        }

        public static void UpdateDatabaseSchema(params Assembly[] assemblies)
        {
            string conn = GetConnectionString();
            IDataLayer datalayer = XpoDefault.GetDataLayer(conn, AutoCreateOption.DatabaseAndSchema);
            using (Session session = new Session(datalayer))
            {
                session.UpdateSchema(assemblies);
                session.CreateObjectTypeRecords(assemblies);
            }
        }

        readonly static object lockObjectOfThreadSafe = new object();

        static volatile IDataLayer fThreadSafeDataLayer;

        static IDataLayer DataLayer
        {
            get
            {
                if (fThreadSafeDataLayer == null)
                {
                    lock (lockObjectOfThreadSafe)
                    {
                        if (fThreadSafeDataLayer == null)
                        {
                            fThreadSafeDataLayer = CreateThreadSafeDataLayer();
                        }
                    }
                }
                return fThreadSafeDataLayer;
            }
        }

        static IDataLayer CreateThreadSafeDataLayer(params Assembly[] assemblies)
        {
            IDataLayer datalayer = GetDataLayer(assemblies);

            XpoDefault.DataLayer = datalayer;

            XpoDefault.Session = null;

            return datalayer;
        }

        static IDataLayer GetDataLayer(params Assembly[] assemblies)
        {
            ReflectionDictionary dict = new ReflectionDictionary();
            dict.CollectClassInfos(assemblies);

            IDataLayer dataLayer;

            int maxConnections = GetMaxConnections();

            if (maxConnections > 1)
            {
                IDataStore[] stores = new IDataStore[maxConnections];
                for (int i = 0; i < maxConnections; i++)
                    stores[i] = GetDataStore();
                dataLayer = new ThreadSafeDataLayer(dict, new DataStoreFork(stores));
            }
            else
            {
                dataLayer = new ThreadSafeDataLayer(dict, GetDataStore());
            }

            return dataLayer;
        }

        static int GetMaxConnections()
        {
            AppSettingsReader config = new AppSettingsReader();
            int conns;
            try
            {
                conns = (int)config.GetValue("DatabaseMaxConnections", typeof(int));
            }
            catch
            {
                conns = 1;
            }
            return conns;
        }

        static IDataStore GetDataStore()
        {
            string conn = GetConnectionString();

            IDataStore store = XpoDefault.GetConnectionProvider(conn, AutoCreateOption.None);

            return store;
        }

        static string GetConnectionString()
        {
            string databaseLocation = System.Windows.Forms.Application.StartupPath;
            databaseLocation += "\\Data\\LY2017.db";
            return SQLiteConnectionProvider.GetConnectionString(databaseLocation);
            //return MySqlConnectionProvider.GetConnectionString();
            //string conn = "XpoProvider=MSSqlServer;Data Source=(local);User ID=sa;Password=sa;Initial Catalog=Oils2015;Persist Security Info=true";
            //return conn;
        }
    }
}
